#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <string.h>
#include "globle.h"
#include "ipc_member.h"

#define LOG_TAG "data_interface.c :"

void *generate_share_memory(xdma_usr_dev *dev,int *shmid,int channel_number)
{
    key_t tmp_key = -1;
    uint32_t size = 0;
    int tmp_id = -1;
    char *tmp_ptr = NULL;
    int id = 0;
    if (!dev)
    {
        LOGE(LOG_TAG"generate_share_memory(),illegal arg,\r\n");
        return NULL;
    }
    size = dev->user_side_ring_buffer_block_num * dev->user_side_ring_buffer_block_size;

    id = (dev->direction == C2H_READ_DATA) ? SHARE_MEM_KEY_ID_READ[channel_number] : SHARE_MEM_KEY_ID_WRITE[channel_number];
    tmp_key = ftok(SHARE_MEM_KEY_PATH,id);
    if (tmp_key < 0)
    {
        LOGE(LOG_TAG"ftok gen key failed,errno = %d\r\n", errno);
        return NULL;
    }

    tmp_id = shmget(tmp_key, size + BLOCK_ALIGN, IPC_CREAT | 0666);
    if (tmp_id < 0)
    {
        LOGE(LOG_TAG"shmget failed,errno = %d\r\n", errno);
        return NULL;
    }

    tmp_ptr = shmat(tmp_id, NULL, 0);
    if (tmp_ptr < 0)
    {
        LOGE(LOG_TAG"shmat failed,errno = %d\r\n", errno);
        return NULL;
    }
    *shmid = tmp_id;

    return tmp_ptr;
}

int destroy_share_memory(const void *shmaddr,int shmid)
{
    if (shmaddr)
    {
        RETURN_ERR(LOG_TAG, "shmdt", shmdt(shmaddr) < 0, 0);
        RETURN_ERR(LOG_TAG, "shmctl", shmctl(shmid, IPC_RMID, NULL) < 0, 1);
    }
    return 0;
}

int generate_msg_queue(xdma_usr_dev *dev,int channel_number)
{
    key_t tmp_key = -1;
    int ret_val = -1;
    int tmp_id = -1;
    struct msqid_ds msg_tmp_buf;

    if (!dev)
    {
        LOGE(LOG_TAG"generate_share_memory(),illegal arg,\r\n");
        return -EINVAL;
    }

    tmp_key = ftok(MSG_QUEUE_KEY_PATH, (dev->direction == C2H_READ_DATA) ? MSG_QUEUE_KEY_ID_READ[channel_number] : MSG_QUEUE_KEY_ID_WRIRE[channel_number]);
    if (tmp_key < 0)
    {
        LOGE(LOG_TAG"ftok gen key failed,errno = %d\r\n", errno);
        return -errno;
    }

    tmp_id = msgget(tmp_key, 0666 | IPC_CREAT);
    RETURN_ERR(LOG_TAG, "msgget", tmp_id < 0, 1);

    memset(&msg_tmp_buf, '\0', sizeof(struct msqid_ds));
    ret_val = msgctl(tmp_id, IPC_STAT, &msg_tmp_buf); //get msg config info
    if (ret_val < 0)
    {
        LOGE(LOG_TAG"msgctl(IPC_STAT) failed for get msg_info,errno = %d\r\n", errno);
        msgctl(tmp_id, IPC_RMID, 0);
        return -errno;
    }

    LOG("default Maximum number of bytes allowed in queue:%lu bytes\r\n", msg_tmp_buf.msg_qbytes);

    msg_tmp_buf.msg_qbytes = dev->fpga_side_ring_buffer_block_num * sizeof(msg_st);//set the max bytes allowed in queue
    ret_val = msgctl(tmp_id, IPC_SET, &msg_tmp_buf); //write back the config info
    if (ret_val < 0)
    {
        LOGE(LOG_TAG"msgctl(IPC_SET) failed for set msg_info,errno = %d\r\n", errno);
        msgctl(tmp_id, IPC_RMID, 0);
        return -errno;
    }

    memset(&msg_tmp_buf, '\0', sizeof(struct msqid_ds));
    ret_val = msgctl(tmp_id, IPC_STAT, &msg_tmp_buf); //get msg config info
    if (ret_val < 0)
    {
        LOGE(LOG_TAG"msgctl(IPC_STAT) failed for get msg_info,errno = %d\r\n", errno);
        msgctl(tmp_id, IPC_RMID, 0);
        return -errno;
    }
    LOG("reset Maximum number of bytes allowed in queue:%lu bytes\r\n", msg_tmp_buf.msg_qbytes);

    return tmp_id;
}

int destroy_msg_queue(int msg_id)
{
    RETURN_ERR(LOG_TAG, "msgctl(IPC_RMID) c2h msgid", msgctl(msg_id, IPC_RMID, 0) < 0, 1);
    return 0;
}

int snd_block_id(xdma_usr_dev *dev, uint32_t block_id, uint32_t block_type,int channel_num)
{
    int ret_val = 0;
    dev->c2h_msg_st[channel_num].block.block_type = block_type;
    dev->c2h_msg_st[channel_num].block.block_number = block_id;
    dev->c2h_msg_st[channel_num].block.block_size = dev->user_side_ring_buffer_block_size;
    ret_val = msgsnd(dev->c2h_msg_queue_id[channel_num], (const void *)(&(dev->c2h_msg_st[channel_num])), sizeof(dev->c2h_msg_st[channel_num].block), 0);
    if (ret_val < 0)
    {
        LOGE(LOG_TAG"msgsnd failed,errno = %d\r\n", errno);
        return -errno;
    }
    dev->deliver_data_len[channel_num] +=  dev->user_side_ring_buffer_block_size;
    return 0;
}

int rcv_block_id(xdma_usr_dev *dev,int channel_num)
{
    int ret_val = 0;
    ret_val = msgrcv(dev->h2c_msg_queue_id[channel_num], (void*)(&(dev->h2c_msg_st[channel_num])), BUFSIZ, dev->h2c_msg_st[channel_num].msg_type, 0);
    if (ret_val < 0)
    {
        LOGE(LOG_TAG"msgrcv failed,errno = %d\r\n", errno);
        return -errno;
    }
    dev->rcv_data_len[channel_num] +=  dev->h2c_msg_st[channel_num].block.block_size;

    return dev->h2c_msg_st[channel_num].block.block_number;
}
